package cc.rengu.igas.mcps.core.realize.impl;

import cc.rengu.igas.mcps.common.constant.McpsParamConstant;
import cc.rengu.igas.mcps.common.dao.TermKeyMapper;
import cc.rengu.igas.mcps.common.dao.impl.TermKeyMapperImpl;
import cc.rengu.igas.mcps.common.entity.TermKey;
import cc.rengu.igas.mcps.common.enums.KeyTypeEnum;
import cc.rengu.igas.mcps.common.enums.RespCodeEnum;
import cc.rengu.igas.mcps.core.realize.PosHsmService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.KeyInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.KeyInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.KeyInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.common.enums.PinTypeEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.HsmService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.HsmServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;

public class PosHsmServiceImpl implements PosHsmService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public void checkPin(String instId, String cardNo, PinTypeEnum pinType, String pinData, String pinCheckValue) throws Exception {
        //TODO 获取密钥标签等信息
        String srcKeyTag = "";
        String dstKeyTag = "";
        HsmService hsmService = new HsmServiceImpl();
        boolean checkResult = hsmService.hsmVerifyPin(instId, srcKeyTag, dstKeyTag, cardNo, pinType, pinData, pinCheckValue);
        if (!checkResult) {
            rglog.error("密码校验失败!");
            throw new BizException(RespCodeEnum.PASS_WORD_CHECK_ERROR.getRespCode(), RespCodeEnum.PASS_WORD_CHECK_ERROR.getRespDesc());
        }
    }

    @Override
    public String transPin(String instId, String mchntNo, String termNo, String cardNo, String dstChannelId, String pinData) throws Exception {
        /* 获取终端工作密钥 */
        TermKeyMapper termKeyMapper = new TermKeyMapperImpl();
        TermKey tpkTermkey = termKeyMapper.getTermKey(instId, mchntNo, termNo, KeyTypeEnum.TPK.getTypeCode());
        if (tpkTermkey == null) {
            rglog.error("未获取到敏感信息加密密钥，拒绝交易");
            throw new BizException(RespCodeEnum.MCHNT_APP_SECRTT_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_APP_SECRTT_NOT_FOUND.getRespDesc());
        }
        /* 获取通道密钥 */
        String dstChannelInfoKey = instId + dstChannelId;
        DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelInfoKey), DstChannelInfo.class);
        if (null == dstChannelInfo) {
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, dstChannelId);
            if (null == dstChannelInfo || StringUtil.isEmptyOrNull(dstChannelInfo.getSecPlanId())) {
                rglog.error("支付通道<{}>未配置或已停用！", dstChannelId);
                throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
            }
        }
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        SecPlanInfo secPlanInfo = secPlanInfoMapper.selectSecPlanInfoByPrimaryKey(instId, dstChannelInfo.getSecPlanId(), McpsParamConstant.PIN_KEY_TYPE);
        if (null == secPlanInfo) {
            rglog.error("安全计划查询为空！instId:<{}>,secPlanId:<{}>,secPlanType:<{}>", instId, dstChannelInfo.getSecPlanId(), McpsParamConstant.PRIVATE_DECRYPT_CERT_TYPE);
            throw new BizException(RespCodeEnum.CERT_INFO_NOT_EXIST.getRespCode(), "机构安全计划查询为空");
        } else if (AppParamConstant.NO.equals(secPlanInfo.getSecPlanStatus())) {
            rglog.error("安全计划状态已失效！instId:<{}>,secPlanId:<{}>,secPlanType:<{}>,状态:<{}>", instId, dstChannelInfo.getSecPlanId(), McpsParamConstant.PRIVATE_DECRYPT_CERT_TYPE, secPlanInfo.getSecPlanStatus());
            throw new BizException(RespCodeEnum.CERT_INFO_NOT_EXIST.getRespCode(), "机构安全计划状态失效");
        }
        KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
        KeyInfo pinKeyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(instId + secPlanInfo.getSecPlanId() + secPlanInfo.getSecPlanType());
        /* 查询转加密方式：空或者0-软加密，其它-硬加密 */
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(instId, McpsParamConstant.MCPS_SYS_ID, McpsParamConstant.ENC_TYPE);
        String encType = null == sysParam ? "0" : sysParam.getParamValue().trim();
        if ("0".equals(encType)) {
            rglog.info("使用软加密方式进行转PIN!");
            if ("3DES".equals(tpkTermkey.getAlgorithmType()) && "3DES".equals(pinKeyInfo.getAlgorithmType())) {
                return PINUtil.transPinDes3ToDes3(pinData, tpkTermkey.getKeyValue(), cardNo, pinKeyInfo.getKeyValue());
            } else if ("SM4".equals(tpkTermkey.getAlgorithmType()) && "SM4".equals(pinKeyInfo.getAlgorithmType())) {
                return PINUtil.transPinSm4ToSm4(pinData, tpkTermkey.getKeyValue(), cardNo, pinKeyInfo.getKeyValue());
            } else if ("3DES".equals(tpkTermkey.getAlgorithmType()) && "SM4".equals(pinKeyInfo.getAlgorithmType())) {
                return PINUtil.transPinDes3ToSm4(pinData, tpkTermkey.getKeyValue(), cardNo, pinKeyInfo.getKeyValue());
            }
        } else {
            /* 硬加密 */
            rglog.info("使用硬加密方式进行转PIN!");
            HsmService hsmService = new HsmServiceImpl();
            return hsmService.hsmTranslatePin(instId, tpkTermkey.getKeyValue(), cardNo, pinKeyInfo.getKeyValue(), cardNo, pinData);
        }
        return null;
    }

    @Override
    public String descriptData(TermKey tdkTermkey, String encData) throws Exception {
        /* 查询转加密方式：空或者0-软加密，其它-硬加密 */
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(tdkTermkey.getInstId(), McpsParamConstant.MCPS_SYS_ID, McpsParamConstant.ENC_TYPE);
        String encType = null == sysParam ? "0" : sysParam.getParamValue().trim();
        if ("0".equals(encType)) {
            rglog.debug("使用软解密,算法类型:<{}>,", tdkTermkey.getAlgorithmType());
            if ("3DES".equals(tdkTermkey.getAlgorithmType())) {
                byte[] descData = DES3Util.decryptMode3DESDouble(ByteUtil.hexStringToByte(tdkTermkey.getKeyValue()), Base64.decodeBase64(encData));
                if (descData != null) {
                    return new String(descData);
                }
            } else {
                byte[] bEncData = Base64.decodeBase64(encData);
                byte[] descData = new byte[bEncData.length];
                int retCode = SM4Util.sms4(bEncData, bEncData.length, ByteUtil.hexStringToByte(tdkTermkey.getKeyValue()), descData, 0);
                if (retCode == 0) {
                    for (int i = 0; i < descData.length; i++) {
                        if (descData[i] == 0) {
                            return new String(descData, 0, i);
                        }
                    }
                    return new String(descData);
                }
            }
        } else {
            /* 硬解密 */
            rglog.debug("使用硬解密,算法类型:<{}>,", tdkTermkey.getAlgorithmType());
            HsmService hsmService = new HsmServiceImpl();
            return hsmService.hsmDecryptData(tdkTermkey.getInstId(), tdkTermkey.getKeyIndex(), tdkTermkey.getAlgorithmType(), encData);
        }
        return null;
    }
}
